package cn.sytton.taffe.job.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.sytton.taffe.framework.base.service.BaseService;
import cn.sytton.taffe.job.constants.ScheduleConstants;
import cn.sytton.taffe.job.entity.JobEntity;
import cn.sytton.taffe.job.mapper.JobLogMapper;
import cn.sytton.taffe.job.mapper.JobMapper;
import cn.sytton.taffe.job.service.IJobService;
import cn.sytton.taffe.job.util.CronUtils;
import cn.sytton.taffe.job.util.ScheduleUtils;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 定时任务服务层
 *
 * @author skyrock
 */
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class JobService extends BaseService<JobMapper, JobEntity> implements IJobService {

    private final Scheduler scheduler;
    private final JobLogMapper jobLogMapper;

    @Override
    @SneakyThrows
    public void create(JobEntity entity) {
        entity.setStatus(0); //新增强制暂停
        boolean success = super.save(entity);
        if (success) {
            ScheduleUtils.createScheduleJob(scheduler, entity);
        }
    }

    @Override
    @SneakyThrows
    public void update(JobEntity entity) {
        boolean success = super.updateById(entity);
        if (success) {
            // 判断是否存在
            JobKey jobKey = ScheduleUtils.getJobKey(entity.getJobId(), entity.getJobGroup());
            if (scheduler.checkExists(jobKey)) {
                // 防止创建时存在数据问题 先移除，然后在执行创建操作
                scheduler.deleteJob(jobKey);
            }
            ScheduleUtils.createScheduleJob(scheduler, entity);
        }
    }

    @Override
    @SneakyThrows
    public void delete(String... ids) {
        for (String id : ids) {
            JobEntity entity = findById(id);
            String jobId = entity.getJobId();
            String jobGroup = entity.getJobGroup();
            boolean success = super.removeById(id);
            if (success) {
                scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));
            }
        }
    }

    @Override
    @SneakyThrows
    public void updateStatus(JobEntity entity) {
        boolean success = update(new LambdaUpdateWrapper<JobEntity>()
                            .set(JobEntity::getStatus, entity.getStatus())
                            .eq(JobEntity::getJobId, entity.getJobId()));
        //todo updatedUserId updatedTime 是否更新
        if (success) {
            if (entity.getStatus() == 0) {
                scheduler.pauseJob(ScheduleUtils.getJobKey(entity.getJobId(), entity.getJobGroup()));
            }
            if (entity.getStatus() == 1) {
                scheduler.resumeJob(ScheduleUtils.getJobKey(entity.getJobId(), entity.getJobGroup()));
            }
        }
    }

    @Override
    @SneakyThrows
    public void run(JobEntity entity) {
        JobEntity properties = findById(entity.getJobId());
        // 参数
        JobDataMap dataMap = new JobDataMap();
        dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
        JobKey jobKey = ScheduleUtils.getJobKey(entity.getJobId(), entity.getJobGroup());
        if (scheduler.checkExists(jobKey)) {
            scheduler.triggerJob(jobKey, dataMap);
        }
    }

    @Override
    public Map<String, Object> findRunInfo(String jobId) {
        Map<String, Object> result = new HashMap<>();
        JobEntity jobEntity = findById(jobId);
        if (jobEntity == null) {
            return result;
        } else {
            int total = 0;
            result.put("failCount", 0);
            result.put("successCount", 0);
            List<Map<String, Object>> countInfo = jobLogMapper.findCountByJobName(jobEntity.getJobName());
            for (Map<String, Object> c : countInfo) {
                if (c.get("status").toString().equals("0")) {
                    result.put("failCount", c.get("num"));
                    total += Integer.parseInt(c.get("num").toString());
                } else if (c.get("status").toString().equals("1")) {
                    result.put("successCount", c.get("num"));
                    total += Integer.parseInt(c.get("num").toString());
                }
            }
            result.put("totalCount", total);
            result.put("nextExecTime", DateUtil.formatDateTime(CronUtils.getNextExecution(jobEntity.getCronExpression())));
        }
        return result;
    }
}
